/*
 * Lenovo Group
 * Copyright (c) 2015-2016 All Rights Reserved.
 * 
 * Project Name:assign-tracer
 * Create Time: 2016年2月25日 下午2:19:30
 */
package com.lenovo.lmrp.server.assigntracer.facade;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import javax.inject.Inject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.lenovo.lmrp.api.constant.EvaluateResults;
import com.lenovo.lmrp.api.constant.SendType;
import com.lenovo.lmrp.api.constant.TicketAction;
import com.lenovo.lmrp.api.constant.TicketPolicy;
import com.lenovo.lmrp.api.constant.TicketStatus;
import com.lenovo.lmrp.api.itsmgateway.IItsmTicket;
import com.lenovo.lmrp.api.model.RestResponse;
import com.lenovo.lmrp.api.model.entity.AssigningTicketPO;
import com.lenovo.lmrp.api.model.entity.EngineerPO;
import com.lenovo.lmrp.api.model.entity.TicketExtensePO;
import com.lenovo.lmrp.api.model.entity.TicketPO;
import com.lenovo.lmrp.api.model.entity.TicketPartsPO;
import com.lenovo.lmrp.api.model.entity.TicketPartsPO.PartsAction;
import com.lenovo.lmrp.api.model.entity.TicketSLAPO;
import com.lenovo.lmrp.api.model.view.ChangedTicketVO;
import com.lenovo.lmrp.api.model.view.PartsVO;
import com.lenovo.lmrp.server.assigntracer.RestClientFactory;
import com.lenovo.lmrp.server.assigntracer.util.pusher.PushParameter;
import com.lenovo.lmrp.server.assigntracer.util.pusher.SenderUtil;
import com.lenovo.sdc.framework.dao.ADaoFactory;
import com.lenovo.sdc.framework.dao.ICommonDAO;
import com.lenovo.sdc.framework.dao.ICommonDAO.FinderEnum;
import com.lenovo.sdc.framework.dao.RecordFilter;
import com.lenovo.sdc.framework.rest.RestClientProxy;
import com.lenovo.sdc.framework.util.AttributeBean;
import com.lenovo.sdc.framework.util.CommonUtil;
import com.lenovo.sdc.framework.util.Condition;
import com.lenovo.sdc.framework.util.Condition.RelationEnum;
import com.lenovo.sdc.framework.util.JSONHelper;
import com.lenovo.sdc.framework.util.exception.ErrorCode;
import com.lenovo.sdc.framework.util.exception.TraceableException;

/**
 * 
 * @author wujin
 * @version v1.0
 */
public class EngineerActionFacadeImpl implements IEngineerActionFacade {

	private static final Logger logger = LoggerFactory.getLogger(EngineerActionFacadeImpl.class);
	private static final String DEFAULT_TIMEOUT = "PT2H";

	private AttributeBean param;

	@Inject
	public void set(AttributeBean param) {
		this.param = param;
	}

	@Override
	public String doConfirm(String itsmCode, ChangedTicketVO changedVO) {
		logger.debug("{} ticket {} do {} ", itsmCode, changedVO.getTicketid(), changedVO.getAction());
		TicketAction actionEnum = TicketAction.valueOf(changedVO.getAction().toUpperCase());
		switch (actionEnum) {
		// 抢单or接单
		case CONFIRM:
			try (ICommonDAO dao = ADaoFactory.getDefault().createDAO(itsmCode)) {
				// 确认接单后，更新工单状态为 执行中
				dao.beginTrans();
				TicketPO ticketPO = dao.get(TicketPO.class, changedVO.getTicketid());
				ticketPO.setStatus(TicketStatus.INEXCUTION.getStatus());
				ticketPO.setUpdateTime(new Date());
				dao.update(ticketPO);
				// 删除接单池or抢单池记录
				RecordFilter filter = new RecordFilter();
				filter.addCondition(new Condition<String, Object>("ticketId", changedVO.getTicketid()));
				List<AssigningTicketPO> pos = dao.filteByCondition(AssigningTicketPO.class, filter);
				for (AssigningTicketPO assigningTicketPO : pos) {
					dao.delete(assigningTicketPO);
				}
				dao.endTrans();
			} catch (Exception exp) {
				throw new TraceableException(ErrorCode.DB_TRANS_FAILED, exp);
			}
			break;
		// 退单
		case REJECT:
			try (ICommonDAO dao = ADaoFactory.getDefault().createDAO(itsmCode)) {
				List<AssigningTicketPO> assignPOs = dao.filteByCondition(AssigningTicketPO.class, new RecordFilter()
						.addCondition(new Condition<String, Object>("ticketid", changedVO.getTicketid()))
						.addCondition(new Condition<String, Object>("assignpolicy", TicketPolicy.ACCEPT.getPolicy()),
								RelationEnum.AND));
				TicketPO ticketPO = dao.get(TicketPO.class, changedVO.getTicketid());
				ticketPO.setStatus(TicketStatus.REJECTED.getStatus());
				dao.beginTrans();
				dao.update(ticketPO);
				for (AssigningTicketPO po : assignPOs) {
					dao.delete(po);
				}
				dao.endTrans();
			} catch (Exception exp) {
				throw new TraceableException(ErrorCode.DB_TRANS_FAILED, exp);
			}
			break;
		// 下次再约
		case RECONFIRM:
			// 恢复工单的SLA信息
			try (ICommonDAO dao = ADaoFactory.getDefault().createDAO(itsmCode)) {
				String hql = "from TicketSLAPO where ticketId = ?";
				List<TicketSLAPO> slas = dao.getRegisteredFinder(FinderEnum.HQL).findMappedRecord(hql,
						TicketSLAPO.class, new String[] { changedVO.getTicketid() });
				dao.beginTrans();
				for (TicketSLAPO sla : slas) {
					sla.setFinished(false);
					dao.update(sla);
				}
				dao.endTrans();
			} catch (Exception exp) {
				throw new TraceableException(ErrorCode.DB_TRANS_FAILED, exp);
			}
			break;
		default:
			throw new TraceableException(ErrorCode.COMM_PARAM_INVALID, "wrong action!");
		}
		// 同步工单数据到itsm系统
		syncItsm(itsmCode, changedVO);
		return DEFAULT_TIMEOUT;
	}

	@Override
	public String doAppoint(String itsmCode, ChangedTicketVO changedVO) {

		TicketAction actionEnum = TicketAction.valueOf(changedVO.getAction().toUpperCase());

		try (ICommonDAO dao = ADaoFactory.getDefault().createDAO(itsmCode)) {
			TicketPO ticket = dao.get(TicketPO.class, changedVO.getTicketid());
			// 预约上门时间
			String appointment = changedVO.getFields().get("appointment");
			// 改约上门时间
			String pendingtime = changedVO.getFields().get("pendingtime");
			boolean isdirty = false;
			// 实际上门地址经纬度
			try {
				String latitude = changedVO.getFields().get("latitude");
				String longitude = changedVO.getFields().get("longitude");
				
				ticket.setLatitude(Double.valueOf(latitude));
				ticket.setLongitude(Double.valueOf(longitude));
				isdirty = true;
			} catch (Exception e) {
				logger.warn("error when update ticket latitude and longitude");
			}

			String hql = "from TicketSLAPO where ticketId = ? order by step";
			List<TicketSLAPO> slas = dao.getRegisteredFinder(FinderEnum.HQL).findMappedRecord(hql, TicketSLAPO.class,
					new String[] { changedVO.getTicketid() });

			dao.beginTrans();
			// 预约完成后 SLA信息中把预约时效屏蔽
			TicketSLAPO responseSla = slas.get(0);
			responseSla.setFinished(true);
			dao.update(responseSla);
			// 上门超时时间改为页面传过来的时间
			TicketSLAPO visitSla = slas.get(1);
			String overtime = actionEnum == TicketAction.APPOINT ? appointment : pendingtime;
			if (CommonUtil.nonNullAndEmpty(overtime)) {
				visitSla.setFinished(false);
				visitSla.setOvertime(CommonUtil.getDateFormatter("yyyy-MM-dd HH:mm").parse(overtime));
			}
			dao.update(visitSla);
			if (isdirty) {
				dao.update(ticket);
			}
			dao.endTrans();
		} catch (Exception exp) {
			throw new TraceableException(ErrorCode.DB_TRANS_FAILED, exp);
		}
		// 同步数据到itsm系统
		syncItsm(itsmCode, changedVO);
		return DEFAULT_TIMEOUT;
	}

	@Override
	public String doVisit(String itsmCode, ChangedTicketVO changedVO) {
		// 签到完成后 SLA信息中把到场时效屏蔽
		try (ICommonDAO dao = ADaoFactory.getDefault().createDAO(itsmCode)) {
			String hql = "from TicketSLAPO where ticketId = ? and finished = 0 order by step";
			TicketSLAPO sla = dao.getRegisteredFinder(FinderEnum.HQL).getSingleRecord(hql, TicketSLAPO.class,
					new String[] { changedVO.getTicketid() });
			if (Objects.nonNull(sla)) {
				sla.setFinished(true);
				dao.beginTrans();
	            dao.update(sla);
	            dao.endTrans();
			}
		} catch (Exception exp) {
			throw new TraceableException(ErrorCode.DB_TRANS_FAILED, exp);
		}
		// 同步数据到itsm系统
		syncItsm(itsmCode, changedVO);
		return DEFAULT_TIMEOUT;
	}

	@Override
	public String doResolve(String itsmCode, ChangedTicketVO changedVO) {
		logger.debug("doResolve ticket，{} ticket {} do {} ", itsmCode, changedVO.getTicketid(), changedVO.getAction());
		List<TicketPartsPO> partsPOs = new ArrayList<>(0);
		Map<String, String> params = changedVO.getFields();
		// 判断是否有收到输入备件信息
		String upJson = params.get("up");
		String downJson = params.get("down");
		if (logger.isDebugEnabled()) {
			logger.debug("upJson:[{}]", upJson);
			logger.debug("downJson:[{}]", downJson);
		}

		boolean flag = Objects.nonNull(upJson) || Objects.nonNull(downJson);
		if (Objects.nonNull(upJson)) // 将数据录入到备件集合
			partsPOs.addAll(parseToPartsPOList(upJson, changedVO.getTicketid(), true));

		if (Objects.nonNull(downJson)) // 将数据录入到备件集合
			partsPOs.addAll(parseToPartsPOList(downJson, changedVO.getTicketid(), false));

		
		try (ICommonDAO dao = ADaoFactory.getDefault().createDAO(itsmCode)) {
		    //完成后 SLA信息中把完成时效屏蔽
		    String hql = "from TicketSLAPO where ticketId = ? and finished = 0 order by step";
            TicketSLAPO sla = dao.getRegisteredFinder(FinderEnum.HQL).getSingleRecord(hql, TicketSLAPO.class,
                    new String[] { changedVO.getTicketid() });
            
            dao.beginTrans();
            if (Objects.nonNull(sla)) {
                sla.setFinished(true);
                dao.update(sla);
            }
		    // 更新数据库中的工单状态和扩展字段
			TicketPO ticketPO = dao.get(TicketPO.class, changedVO.getTicketid());
			ticketPO.setStatus(TicketStatus.FINISHED.getStatus());
			ticketPO.setUpdateTime(new Date());

			dao.update(ticketPO);
			dao.endTrans();
		} catch (Exception exp) {
			throw new TraceableException(ErrorCode.DB_TRANS_FAILED, exp);
		}
		params.remove("up");
		params.remove("down");
		changedVO.setFields(params);
		if (flag) {// 判断是否向羲和同步备件信息数据
			syncItsm(itsmCode, changedVO, parseToPartsVO(partsPOs));
		} else {
			syncItsm(itsmCode, changedVO);
		}
		return DEFAULT_TIMEOUT;
	}

	@Override
	public String doEvaluate(String itsmCode, ChangedTicketVO changedVO) {
		// 同步到itsm
		syncItsm(itsmCode, changedVO);
		// 评价结果
		String evaluateresults = changedVO.getFields().get("evaluateresults");
		EvaluateResults er = EvaluateResults.values()[Integer.parseInt(evaluateresults)];
		try (ICommonDAO dao = ADaoFactory.getDefault().createDAO(itsmCode)) {
			TicketExtensePO ticketExtensePO = dao.get(TicketExtensePO.class, changedVO.getTicketid());
			// 短信通知最终服务客户
			String actuallCustomerPhone = ticketExtensePO.getAttributeBean().getAttribute("actuallcustomerphone", "");
			List<PushParameter> pushParameters = new ArrayList<PushParameter>();
			if (CommonUtil.nonNullAndEmpty(actuallCustomerPhone)) {
				PushParameter msParameter = new PushParameter();
				msParameter.setMobile(actuallCustomerPhone);
				msParameter.setContent("您对工单号为" + changedVO.getTicketid() + "的服务评价是" + er.getDescr());
				msParameter.setSendType(SendType.SMS);
				pushParameters.add(msParameter);
			}
			// 短信通知工单联系人
			String customerMobile = ticketExtensePO.getAttributeBean().getAttribute("customermobile", "");
			String address = ticketExtensePO.getAttributeBean().getAttribute("address", "");
			String actuallcustomer = ticketExtensePO.getAttributeBean().getAttribute("actuallcustomer", "");
			if (CommonUtil.nonNullAndEmpty(customerMobile)) {
				PushParameter msParameter = new PushParameter();
				msParameter.setMobile(customerMobile);
				String pattern = "联想MS服务单[{0}]，在[{1}] 的服务已完成，最终用户[{2}]对该次服务评价为[{3}]。"
						+ "如果您有任何疑问或建议，可以联系服务台或发送邮件给MSQA@lenovo.com。感谢您对联想服务的大力支持。";
				String content = MessageFormat.format(pattern, changedVO.getTicketid(), address, actuallcustomer,
						er.getDescr());
				msParameter.setContent(content);
				msParameter.setSendType(SendType.SMS);
				pushParameters.add(msParameter);
			}
			SenderUtil.senderMessage(pushParameters);
		} catch (Exception e) {
			logger.warn("ticket {} failed to send evalutate by sms.", changedVO.getTicketid());
		}
		return DEFAULT_TIMEOUT;
	}

	@Override
	public String doClose(String itsmCode, ChangedTicketVO changedVO) {
		logger.debug("{} ticket {} do {} ", itsmCode, changedVO.getTicketid(), changedVO.getAction());
		try (ICommonDAO dao = ADaoFactory.getDefault().createDAO(itsmCode)) {
			TicketAction action = TicketAction.valueOf(changedVO.getAction().toUpperCase());
			TicketPO ticketPO = dao.get(TicketPO.class, changedVO.getTicketid());
			String hql = "from EngineerPO where loginName = ?";
			EngineerPO engineerPO = dao.getRegisteredFinder(FinderEnum.HQL).getSingleRecord(hql, EngineerPO.class,
					new String[] { ticketPO.getAssignee() });
			if (action == TicketAction.CLOSE) {
				// 确认 后，流程结束
				ticketPO.setStatus(TicketStatus.CLOSED.getStatus());
				ticketPO.setUpdateTime(new Date());
				dao.beginTrans();
				dao.update(ticketPO);
				dao.endTrans();
				// 快速关单
			} else if (action == TicketAction.BREAKOFF) {
				// 确认 后，流程结束
				ticketPO.setStatus(TicketStatus.BREAK.getStatus());
				ticketPO.setUpdateTime(new Date());
				String description = "工程师" + engineerPO.getFullName() + ",快速关单时间" + ticketPO.getUpdateTime()
						+ ",工程师快速关单:" + "<" + changedVO.getReason() + ">";
				ticketPO.setDescription(description);
				dao.beginTrans();
				dao.update(ticketPO);
				dao.endTrans();
			}
		} catch (Exception exp) {
			throw new TraceableException(ErrorCode.DB_TRANS_FAILED, exp);
		}
		syncItsm(itsmCode, changedVO);
		return DEFAULT_TIMEOUT;
	}

	@Override
	public boolean doTimeoutAlarm(String step, String itsmCode, String ticketID, String engineerID) {
		if (logger.isDebugEnabled())
			logger.debug("at {} itsm {} ticket {} overtime", step, itsmCode, ticketID);

		if (step.equals("evaluate")) {
			try (ICommonDAO dao = ADaoFactory.getDefault().createDAO(itsmCode)) {
				TicketPO ticketPO = dao.get(TicketPO.class, ticketID);
				if (Objects.isNull(ticketPO))
					return false;
				
				// default timeout is 30 days
				long timeout = (param == null ? 2592000 : param.getAttribute("unevaluate.timeout", 2592000));
				logger.debug("now {} upatetime {} timeout {}", System.currentTimeMillis(), ticketPO.getUpdateTime().getTime(), timeout);
				if ((long)(System.currentTimeMillis() - ticketPO.getUpdateTime().getTime()) > (timeout * 1000L))
					return true;
				else
					return false;
			} catch (Exception exp) {
				return false;
			}
		} else
			return false;
	}

	// 同步数据到itsm系统
	private RestResponse<Integer> syncItsm(String itsmcode, ChangedTicketVO changedVO) {
		RestClientProxy proxy = RestClientFactory.getItsmGatewayClient();
		IItsmTicket itsmTicket = proxy.getService(IItsmTicket.class);
		return itsmTicket.updateTicket(itsmcode, changedVO.getTicketid(), changedVO.getAction(), changedVO);
	}

	// 同步数据（工单和备件）到itsm系统
	private void syncItsm(String itsmcode, ChangedTicketVO changedVO, List<PartsVO> parts) {
		RestClientProxy proxy = RestClientFactory.getItsmGatewayClient();
		IItsmTicket itsmTicket = proxy.getService(IItsmTicket.class);
		itsmTicket.updateTicket(itsmcode, changedVO.getTicketid(), changedVO.getAction(), changedVO);// 同步工单
		itsmTicket.replaceParts(itsmcode, changedVO.getTicketid(), parts);// 同步备件
	}

	// 将Json数据转换成集合
	private List<TicketPartsPO> parseToPartsPOList(String json, String ticketId, boolean isNew) {
		List<TicketPartsPO> list = new ArrayList<>(0);
		try {
			if (CommonUtil.nonNullAndEmpty(json) && json.contains("[") && json.contains("]")) {// 多个数据
				// 替换格式
				json = json.replaceAll("\"\\{", "{").replaceAll("\\}\"", "}").replaceAll("\\\\", "");
				@SuppressWarnings("rawtypes")
				List fromJSON = JSONHelper.fromJSON(json, List.class);
				for (Object object : fromJSON) {
					TicketPartsPO partsPO = JSONHelper.fromJSON(JSONHelper.toJSON(object), TicketPartsPO.class);
					partsPO.setType(isNew ? PartsAction.UP : PartsAction.DOWN);
					partsPO.setTicketId(ticketId);
					list.add(partsPO);
				}
			} else if (CommonUtil.nonNullAndEmpty(json)) {// 单个数据
				TicketPartsPO partsPO = JSONHelper.fromJSON(json, TicketPartsPO.class);
				partsPO.setType(isNew ? PartsAction.UP : PartsAction.DOWN);
				partsPO.setTicketId(ticketId);
				list.add(partsPO);
			}
			return list;
		} catch (Exception e) {
			throw new TraceableException(ErrorCode.COMM_PARSE_FAILED, e);
		}
	}

	// 将TicketPartsPO转换成PartsVO
	private List<PartsVO> parseToPartsVO(List<TicketPartsPO> partsPOs) {
		List<PartsVO> partsVOs = new ArrayList<>(0);
		for (TicketPartsPO ticketPartsPO : partsPOs) {
			PartsVO partsVO = new PartsVO();
			partsVO.setPartsnum(ticketPartsPO.getId());
			partsVO.setFru(ticketPartsPO.getFRU());
			partsVO.setPartsname(ticketPartsPO.getName());
			partsVO.setDescription(ticketPartsPO.getDescription());
			partsVO.setNew(ticketPartsPO.getType() == PartsAction.UP);
			partsVOs.add(partsVO);
		}
		return partsVOs;
	}

}
